﻿Imports System.Text.RegularExpressions
Imports System.Text
Imports System.Threading.Tasks
Imports System.Collections.Concurrent

Public Class TwoLine

	Private Shared _PinyinPhrases As New ConcurrentDictionary(Of String, String)
	Private Shared _ZhuyinPhrases As New ConcurrentDictionary(Of String, String)
	Private Shared _SydneyLauPhrases As New ConcurrentDictionary(Of String, String)

	Private Shared ReadOnly Property TwoLinePhrases(DictionaryType As RomanizationType) As ConcurrentDictionary(Of String, String)
		Get
			Select Case DictionaryType
				Case RomanizationType.Pinyin
					Return _PinyinPhrases
				Case RomanizationType.Zhuyin
					Return _ZhuyinPhrases
				Case RomanizationType.SydneyLau
					Return _SydneyLauPhrases
				Case Else
					Return _PinyinPhrases
			End Select
		End Get
	End Property

	Public Enum RomanizationType As Integer
		None
		Pinyin
		Zhuyin
		SydneyLau
	End Enum

	Private _Romanization As RomanizationType
	Public Property Romanization As RomanizationType
		Get
			Return _Romanization
		End Get
		Set(value As RomanizationType)
			_Romanization = value
			'make sure we get a new ProcessStartInfo
			_startInfo = Nothing
		End Set
	End Property

	Private _startInfo As ProcessStartInfo
	Private ReadOnly Property startInfo As ProcessStartInfo
		Get
			If _startInfo Is Nothing Then
				_startInfo = New ProcessStartInfo()
				_startInfo.UseShellExecute = False 'required to redirect standard input/output

				_startInfo.RedirectStandardInput = True
				_startInfo.RedirectStandardOutput = True
				_startInfo.RedirectStandardError = True
				_startInfo.CreateNoWindow = True
				_startInfo.StandardOutputEncoding = Text.Encoding.UTF8

				Select Case Romanization
					Case RomanizationType.Pinyin
						_startInfo.FileName = "annotator.exe"
					Case RomanizationType.Zhuyin
						_startInfo.FileName = "annozhuyin.exe"
					Case RomanizationType.SydneyLau
						_startInfo.FileName = "annocant.exe"
				End Select
				'_startInfo.Arguments = ...arguments if required...
			End If

			Return _startInfo

		End Get
	End Property

	'Private _converterProcess As Process
	'Private ReadOnly Property converterProcess As Process
	'	Get
	'		If _converterProcess Is Nothing Then
	'			_converterProcess = New Process
	'			_converterProcess.StartInfo = startInfo
	'			_converterProcess.Start()
	'		End If

	'		Return _converterProcess
	'	End Get
	'End Property

	'Private _stdin As IO.StreamWriter
	'Private ReadOnly Property stdin As IO.StreamWriter
	'	Get
	'		If _stdin Is Nothing Then
	'			_stdin = New IO.StreamWriter(converterProcess.StandardInput.BaseStream, Text.Encoding.UTF8)
	'		End If

	'		Return _stdin
	'	End Get
	'End Property

	''Private _stdout As IO.StreamReader
	'Private ReadOnly Property stdout As IO.StreamReader
	'	Get
	'		'If _stdout Is Nothing Then

	'		'End If

	'		Return converterProcess.StandardOutput

	'	End Get
	'End Property

	Public Sub New()
		Romanization = RomanizationType.Pinyin
	End Sub

	Public Sub New(Romanization As RomanizationType)
		Me.Romanization = Romanization
	End Sub

	'http://stackoverflow.com/a/6787041/271351
	'http://stackoverflow.com/a/7812732/271351
	'http://social.msdn.microsoft.com/Forums/vstudio/en-US/46c91711-755f-48fa-a4a8-92956082218f/howto-launch-process-and-write-to-its-stdin?prof=required
	Public Function AddTwoLine(textPage As String) As String

		If Romanization <> RomanizationType.None AndAlso (textPage.Contains(" lang=""zh-Hans""") OrElse textPage.Contains(" lang=""zh-Hans""")) Then

			Dim phrasesRegex As New Regex("(?<=>)[^<>]+(?=<)")
			Dim notChineseRegex As New Regex("^[0-z:;%',""=+?/().*{}&\-\.\s]+$")

			Parallel.ForEach(GetAllTextSegments(textPage, phrasesRegex).Cast(Of Match), Sub(currentElement As Match)
																							'don't process only whitespace or only numbers, letters, and html-specific punctuation
																							If Not String.IsNullOrWhiteSpace(currentElement.Value) AndAlso Not notChineseRegex.IsMatch(currentElement.Value) Then
																								If Not TwoLinePhrases(Romanization).ContainsKey(currentElement.Value) Then
																									TwoLinePhrases(Romanization).TryAdd(currentElement.Value, GetSecondLine(currentElement))
																								End If
																							End If
																						End Sub)

			textPage = phrasesRegex.Replace(textPage, New MatchEvaluator(Function(matchedElement As Match)
																			 If TwoLinePhrases(Romanization).ContainsKey(matchedElement.Value) Then
																				 Return TwoLinePhrases(Romanization)(matchedElement.Value)
																			 Else
																				 Return matchedElement.Value
																			 End If
																		 End Function))
		End If

		Return textPage

	End Function

	Private Function GetAllTextSegments(textPage As String, phrasesRegex As Regex) As MatchCollection
		Return phrasesRegex.Matches(textPage)
	End Function

	Private Function GetSecondLine(ChineseText As Match) As String

		'don't process only whitespace or only numbers, letters, and html-specific punctuation
		'If Not String.IsNullOrWhiteSpace(ChineseText.Value) AndAlso Not Regex.IsMatch(ChineseText.Value, "^[A-Za-z\&\;0-9 ]$") Then

		Using converterProcess As New Process()
			converterProcess.StartInfo = startInfo
			converterProcess.Start()
			Dim sb As New StringBuilder

			Using stdin As New IO.StreamWriter(converterProcess.StandardInput.BaseStream, Text.Encoding.UTF8)
				stdin.AutoFlush = True
				stdin.WriteLine(ChineseText.Value)
			End Using

			Using stdout As IO.StreamReader = converterProcess.StandardOutput
				Dim result As String = stdout.ReadToEnd

				Return result
			End Using
		End Using
		'Else
		'Return ChineseText.Value
		'End If
	End Function

End Class
